/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.swirrel.installer;

import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import java.awt.Component;

import org.swirrel.annotation.PropertyChange;
import org.swirrel.annotation.PropertyChanges;
import org.swirrel.listener.SwirrelPropertyChangeListener;
import org.swirrel.util.MethodCall;
import org.swirrel.util.SwirrelException;
import org.swirrel.util.Tuple;
import java.lang.annotation.Annotation;

/**
 *
 * @author Gronau
 */
public class PropertyChangeListenerInstaller
    extends AbstractListenerInstaller implements SwirrelListenerInstaller {

  public PropertyChangeListenerInstaller() {
    super(Arrays.<Class<? extends Annotation>> asList(PropertyChange.class,
        PropertyChanges.class),
          Arrays.<Class<?>> asList(Component.class));
  }

  public boolean isListenerAlreadySet(Object obj) {
    for (PropertyChangeListener pcl :
         ( (Component) obj).getPropertyChangeListeners()) {
      if (pcl instanceof SwirrelPropertyChangeListener) {
        return true;
      }
    }
    return false;
  }

  @Override
  public List<Tuple<String, Boolean>> getMethodNames(Field field) {
    Tuple<Map<String, String>, Set<String>> tuple = extractMethods(field);
    List<Tuple<String, Boolean>> list = new ArrayList<Tuple<String, Boolean>> ();
    for (String method : tuple.first().values()) {
      list.add(Tuple.of(method, tuple.second().contains(method)));
    }
    return list;
  }

  public void registerListener(Field field, Component comp, List<MethodCall>
      methodCalls) throws IllegalAccessException {
    Map<String, String> annotations = extractMethods(field).first();
    int i = 0;
    Component annotatedComp = (Component) field.get(comp);
    for (String property : annotations.keySet()) {
      MethodCall methodCall = methodCalls.get(i);
      if (property.equals("")) {
        annotatedComp.addPropertyChangeListener(
            new SwirrelPropertyChangeListener(methodCall));
      }
      else {
        annotatedComp.addPropertyChangeListener(property,
                                                new
                                                SwirrelPropertyChangeListener(
            methodCall));
      }
      i++;
    }
  }

  private Tuple<Map<String, String>, Set<String>> extractMethods(Field field) {
    Map<String, String> result = new TreeMap<String, String> ();
    Set<String> threaded = new HashSet<String> ();
    if (field.isAnnotationPresent(PropertyChanges.class)) {
      PropertyChanges pccs = field.getAnnotation(PropertyChanges.class);
      for (PropertyChange pcc : pccs.value()) {
        if (result.containsKey(pcc.property())) {
          throw new SwirrelException("Duplicate property: " + pcc.property());
        }
        result.put(pcc.property(), pcc.method());
        if (pcc.threaded()) {
          threaded.add(pcc.method());
        }
      }
    }
    else if (field.isAnnotationPresent(PropertyChange.class)) {
      PropertyChange pcc = field.getAnnotation(PropertyChange.class);
      result.put(pcc.property(), pcc.method());
      if (pcc.threaded()) {
        threaded.add(pcc.method());
      }
    }
    else {
      throw new SwirrelException("No PropertyChangeCall(s) annotation found");
    }
    return Tuple.of(result, threaded);
  }
}
